home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
4_0
/
STARS.C
< prev
Wrap
C/C++ Source or Header
|
1989-02-09
|
13KB
|
493 lines
#include ":Includes:MemoryMgr.h"
#include ":Includes:DeviceMgr.h"
#include ":Includes:Quickdraw.h"
#include ":Includes:WindowMgr.h"
#include ":Includes:EventMgr.h"
int numStars = 500; /* number of stars */
int inUse = 0; /* number actually in use */
#define xyspan 8000 /* range of the xy space. */
#define zspan 150 /* if you change this, change StarSize */
typedef int **IntHandle;
IntHandle theThrottle; /* resource with permanent throttle setting */
/* Program to get those 'star trek" type stars.
Stars 1.3 by David Phillip Oster, in LightSpeed C
Arpa: oster@lapis.berkeley.edu
Usenet: ucbvax!lapis!oster
originally Aztec C v. 1.06H by Steve Hawley 6/12/86
heavily modified by
David Oster June 13, 1986
David Oster June 14, 1986 - added throttle.
David Oster June 15, 1986 - added throttle memory.
David Oster June 17, 1986 - centered the copybits stars
David Oster June 18, 1986 - added hyper-space effect to throttle.
Hawley says:
I'm very disappointed with the speed, as I've written a similar
program in 6502 assembly that handles 5 times as many stars
faster (this was on a 1 Mhz processor compared to the Mac's 8 Mhz).
My question is, is my C programming that bad or is Aztec C that
poor in performance?
Complaints, etc to:
David Oster
Usenet: ucbvax!ucblapis!oster
ARPA: oster%lapis@berkeley
*/
/*
calling tree:
main
closeDriver
doMain
RsrcID
update - (the heart of the program)
StarSize
DrawStar
FlipPixel
Throttle - ( for initialization )
SetThrottle
HyperThrottle
HyperUpdate
DrawStar
Throttle
rampUp
DrawStar
rampDn
DrawStar
*/
void DrawStar(), HyperThrottle();
struct starRec { /* define a star as an x,y,z point */
int y,x,z; /* keep it compatible with a mac point */
};
struct star {
struct starRec pos, draw;
} *galaxy;
WindowPtr myWindow;
/* abs - returns absolute value of its argument
*/
int abs(i)int i;{
if (i < 0) return(-i);
else return(i);
}
/* 150 - 60 = 1
59 - 30 = 2
29 - 15 = 3
15 - 0 = 4 star size depends on distance. closer is bigger
*/
/* StarSize - map star's z into a small size.
*/
int StarSize(z)int z;{
return z > 60 ? 1 : (z > 30 ? 2 : (z > 15 ? 3 : 4));
}
/* rampUp - add stars to the galaxy.
*
*/
rampUp(toAdd)int toAdd;{
register struct star *aStar;
struct star *galaxyEnd;
register int i, size;
galaxyEnd = galaxy + inUse + toAdd;
for (aStar = galaxy+inUse; aStar < galaxyEnd; aStar++) {
aStar->pos.x = Random() % xyspan;
aStar->pos.y = Random() % xyspan;
aStar->pos.z = abs(Random() % zspan);
/* set up stars */
if (aStar->pos.z == 0) aStar->pos.z =1;
/*draw all stars with one-point perspective using
the formulae x' = x/z; y' = y/z */
DrawStar(srcXor,
aStar->draw.x = aStar->pos.x/aStar->pos.z,
aStar->draw.y = aStar->pos.y/aStar->pos.z,
aStar->draw.z = StarSize(aStar->pos.z));
}
inUse += toAdd;
}
/* rampDn - remove stars from the galaxy
*
*/
rampDn(toSub)int toSub;{
register struct star *aStar;
struct star *galaxyEnd;
register int i, size;
galaxyEnd = galaxy + inUse;
for (aStar = galaxy + inUse - toSub; aStar < galaxyEnd; aStar++) {
/* undraw all stars with one-point perspective using
the formulae x' = x/z; y' = y/z */
DrawStar(srcXor, aStar->draw.x, aStar->draw.y, aStar->draw.z);
}
inUse -= toSub;
}
/* update - do one animation step
* update the model for all stars, and redraw those that need it.
*/
update(){
register struct star *aStar;
struct star *galaxyEnd;
struct starRec new;
galaxyEnd = galaxy + inUse;
for (aStar = galaxy; aStar < galaxyEnd; aStar++) {
aStar->pos.z -= 1; /*Update z coordinate */
if (aStar->pos.z <= 0){
/* if star has passed us, make a new one on horizon */
aStar->pos.z = zspan;
aStar->pos.x = Random() % xyspan;
aStar->pos.y = Random() % xyspan;
}
new.x = aStar->pos.x / aStar->pos.z,
new.y = aStar->pos.y / aStar->pos.z,
new.z = StarSize(aStar->pos.z);
if(new.x != aStar->draw.x || /* if it moved, then show it */
new.y != aStar->draw.y ||
new.z != aStar->draw.z){
DrawStar(srcXor, aStar->draw.x, aStar->draw.y, aStar->draw.z);/*undraw new*/
aStar->draw = new;
DrawStar(srcXor, aStar->draw.x, aStar->draw.y, aStar->draw.z);/*draw new*/
}
}
}
/* Xor the pixel at coordinates x, y (direct screen memory access!)
*/
void FlipPixel(x, y)register int x, y;{
register GrafPtr myPort;
register QDPtr theByte;
register QDByte thePixel;
myPort = myWindow;
if( x >= myPort->portBits.bounds.left &&
y >= myPort->portBits.bounds.top &&
x < myPort->portBits.bounds.right &&
y < myPort->portBits.bounds.bottom){
y -= myPort->portBits.bounds.top;
x -= myPort->portBits.bounds.left;
theByte = myPort->portBits.baseAddr + (y * myPort->portBits.rowBytes) + (x >> 3);
thePixel = 0x80 >> (x & 7);
*theByte ^= thePixel;
}
}
/* Set the pixel at coordinates x, y (direct screen memory access!)
*/
void OnPixel(x, y)register int x, y;{
register GrafPtr myPort;
register QDPtr theByte;
register QDByte thePixel;
myPort = myWindow;
if( x >= myPort->portBits.bounds.left &&
y >= myPort->portBits.bounds.top &&
x < myPort->portBits.bounds.right &&
y < myPort->portBits.bounds.bottom){
y -= myPort->portBits.bounds.top;
x -= myPort->portBits.bounds.left;
theByte = myPort->portBits.baseAddr + (y * myPort->portBits.rowBytes) + (x >> 3);
thePixel = 0x80 >> (x & 7);
*theByte |= thePixel;
}
}
/* Clear the pixel at coordinates x, y (direct screen memory access!)
*/
void OffPixel(x, y)register int x, y;{
register GrafPtr myPort;
register QDPtr theByte;
register QDByte thePixel;
myPort = myWindow;
if( x >= myPort->portBits.bounds.left &&
y >= myPort->portBits.bounds.top &&
x < myPort->portBits.bounds.right &&
y < myPort->portBits.bounds.bottom){
y -= myPort->portBits.bounds.top;
x -= myPort->portBits.bounds.left;
theByte = myPort->portBits.baseAddr + (y * myPort->portBits.rowBytes) + (x >> 3);
thePixel = 0xFF7F >> (x & 7);
*theByte &= thePixel;
}
}
/* bitmaps for DrawStar */
char data1[] = "\377"; /* must be 2 chars long */
char data2[] = "\137\337\377\377\137"; /* must be 6 chars long */
short int data3[] = {
0x3000,
0x7C00,
0x7C00,
0x7C00,
0x3000
}; /* must be 10 chars long */
short int data4[] = {
0x3C00,
0x7E00,
0xFF00,
0xFF00,
0xFD00,
0x7A00,
0x3C00,
};
/* As a star grows, we want its center to stay its center.
* Copybits will keep the left corner the left corner.
* The extra rect here is to make it fast to compute the center
*
* This data structure gets its run-time initialization done in doMain
*/
typedef struct { BitMap b; Rect r; } BitStuff;
BitStuff srcBits[] = {
{{ 0L, 2, {0, 0, 1, 1}}, {0, 0, 1, 1} },
{{ 0L, 2, {0, 0, 1, 1}}, {0, 0, 1, 1} },
{{ 0L, 2, {0, 0, 3, 3}}, {-1, -1, 2, 2} },
{{ 0L, 2, {0, 0, 5, 5}}, {-2, -2, 3, 3} },
{{ 0L, 2, {0, 0, 7, 8}}, {-3, -4, 4, 4} },
} ;
/* DrawStar - actually draw a star.
* (this version optimizes for the small star cases)
*/
void DrawStar(tMode, x, y, size){
register void (*ChangePixel)();
register BitStuff *srcPtr;
Rect destRect;
if(tMode == srcXor)
ChangePixel = FlipPixel;
else if(tMode == srcOr)
ChangePixel = OnPixel;
else
ChangePixel = OffPixel;
switch( size ){
case 2 :
(*ChangePixel)(x, y-1); (*ChangePixel)(x, y+1);
(*ChangePixel)(x-1, y); (*ChangePixel)(x+1, y); /* note, we fall through */
case 1 :
(*ChangePixel)(x, y); break;
default :
srcPtr = srcBits + size;
destRect.left = x + srcPtr->r.left;
destRect.top = y + srcPtr->r.top;
destRect.right = x + srcPtr->r.right;
destRect.bottom = y + srcPtr->r.bottom;
CopyBits(&srcPtr->b, &myWindow->portBits,
&srcPtr->b.bounds, &destRect,
tMode, 0L);
}
}
/* speed up by displaying fewer stars, down by displaying more.
*
*/
Throttle(c)int c;{
int toUse;
toUse = numStars * ( (2*(c & 15) + 1)) / 32;
if(toUse > inUse)rampUp(toUse - inUse);
if(toUse < inUse)rampDn(inUse - toUse);
}
/* SetThrottle - permanently change Throttle setting
* handle proprogation of Throttle setting to disk, and call
* throttle to actually change the number of stars.
*
*/
SetThrottle(c)int c;{
LoadResource(theThrottle);
if(**theThrottle != c){
**theThrottle = c;
HNoPurge(theThrottle);
ChangedResource(theThrottle);
}
HyperThrottle(c);
}
/***** hyperspace support routines ******/
/* HyperUpdate - animate galaxy off the screen
* update the model for all stars, and redraw those that need it.
*
* Note: I chose to fix the hyper effect starsize at 1.
*/
HyperUpdate(tMode, galaxyStart, galaxyEnd)
int tMode;
struct star *galaxyStart, *galaxyEnd;
{
register struct star *aStar;
struct starRec new;
int changed;
changed = 1;
while(changed){
changed = 0;
for (aStar = galaxyStart; aStar < galaxyEnd; aStar++) {
aStar->pos.z -= 2; /*Update z coordinate */
if (aStar->pos.z > 0){
new.x = aStar->pos.x / aStar->pos.z,
new.y = aStar->pos.y / aStar->pos.z,
new.z = 1; /* StarSize(aStar->pos.z); */
if(new.x != aStar->draw.x || /* if it moved, then show it */
new.y != aStar->draw.y ||
new.z != aStar->draw.z){
changed = 1; /* a star visibly moved */
aStar->draw = new;
DrawStar(tMode,
aStar->draw.x,
aStar->draw.y,
aStar->draw.z); /*draw new*/
}
}
}
}
}
void HyperThrottle(c)int c;{
struct star *HiGalaxy, *galaxyEnd;
register struct star *aStar, *destStar;
galaxyEnd = galaxy + numStars/16;
HiGalaxy = galaxy + numStars - numStars/16 - 1;
aStar = galaxy; destStar = HiGalaxy;
rampDn(inUse);
while(aStar < galaxyEnd){
*destStar++ = *aStar++;
}
HyperUpdate(srcBic, galaxy, galaxyEnd); /* draw 'em. */
inUse = 0;
HyperUpdate(srcOr, HiGalaxy, HiGalaxy + numStars/16); /* Erase 'em */
Throttle(c);
}
/* To Un-desk-accessory-ify this, just un-comment out the commented out
* lines, and make this the main procedure
*
* It is important to me that the numbers 512, 342 not appear in my code.
* some people still have lisa's
*/
doMain()
{ EventRecord myEvent;
long int space;
int i;
Rect bigRect;
SetRect(&bigRect, 0, 0, 10000, 10000);
myWindow = NewWindow(0L, &bigRect, "\p",
0, 0, (char*) -1, 1, 0L);
space = CompactMem((long) maxSize) / sizeof(struct star);
if(space > 1000) /* space for other things */
space -= 1000;
if(space < numStars)
numStars = space;
galaxy = (struct star *) NewPtr(numStars-- * (long) sizeof(struct star));
if(galaxy != 0L){
/* InitGraf(&thePort); /* do inits */
/* InitWindows(); */
/* SetCursor(&arrow); */
FlushEvents(everyEvent,0);
HideCursor();
SetPort(myWindow);
ShowWindow(myWindow);
InitPort(myWindow); /* set port to entire screen, no menubar! */
BackPat(myWindow->pnPat); /* black */
EraseRect(&myWindow->portRect); /* flip screen to black */
SetOrigin(-myWindow->portRect.right / 2,
-myWindow->portRect.bottom / 2);
PenMode(patXor); /*use exclusive-or drawing to ease programming */
if(myWindow->portBits.baseAddr != 0L) {
srcBits[0].b.baseAddr = (QDPtr) &data1;
srcBits[1].b.baseAddr = (QDPtr) &data1;
srcBits[2].b.baseAddr = (QDPtr) &data2;
srcBits[3].b.baseAddr = (QDPtr) &data3;
srcBits[4].b.baseAddr = (QDPtr) &data4;
/* initialize galaxy */
theThrottle = (IntHandle) GetResource('GNRL', RsrcID(0));
HPurge(theThrottle);
Throttle(**theThrottle);
/* do until mousedown, or until user hits a command key */
myEvent.what = nullEvent;
while( ! ( (myEvent.what == mouseDown) ||
(myEvent.what == keyDown && (myEvent.modifiers & cmdKey)) )){
if(myEvent.what == keyDown){
SetThrottle((int) myEvent.message & 0xFF);
}
update(); /* animate until moused */
SystemTask();
GetNextEvent(mDownMask+keyDownMask, &myEvent);
}
}
DisposPtr( (Ptr) galaxy);
DisposeWindow(myWindow);
DrawMenuBar();
ShowCursor();
}
}
/*
* main program
*
* The first two arguments are the values passed in registers A0/A1
* to an assembly-language desk accessory. The third argument is a
* selector indicating which entry point was called.
*/
DCtlPtr dce; /* desk acc global to get at device control entry */
main(p, d, n)
cntrlParam *p; /* ==> parameter block */
DCtlPtr d; /* ==> device control entry */
int n; /* entry point selector */
{
if (d->dCtlStorage == 0) {
if (n == 0) { /* open, but no data */
SysBeep(3);
CloseDriver(d->dCtlRefNum);
}
return(0);
}
dce = d;
/* dispatch */
if( n == 0){ /* i.e, an Open */
doMain();
CloseDriver(d->dCtlRefNum);
}
}
/* ---------- resource handling ---------- */
/*
* RsrcID - compute ID of owned resource
*
* This is a magic formula by which we can compute the IDs of our
* resources no matter what driver number Font/DA-Mover has assigned
* us. See the Resource Manager chapter of Inside Macintosh for more
* information about "owned" resources.
*/
int RsrcID(id)int id;{
return 0xC000 + (~dce->dCtlRefNum << 5) + id;
}